/**
 * @author liangxi
 * @since 2023/12/21
 */

#ifndef DESIGNPATTERN_SINGLETON1_H
#define DESIGNPATTERN_SINGLETON1_H


#include <mutex>

namespace Singleton {
    /**
     * 此例子为懒汉式，在使用的时候才去创建实例，如果不加判空机制，在多线程环境下很难保证程序的正确性
     * 线程安全实现方式之一：双重判空加锁,但由于reorder(编译器优化后，指令的执行顺序可能和想象的不一样)不安全。
     */
    class [[maybe_unused]] Singleton1 {
    public:

        /**
         * @details
         * 在instance = new Singleton1()时，一般情况下有三步：
         *  1. 分配内存；2. 执行构造器； 3. 将指针转化并赋给在instance；
         *  但是在reorder之后，2和3两步可能顺序倒过来，这样有其它线程执行该方法，第一次判空不空，直接return
         *  出去的对象可能还没有执行构造器，使用起来会出现问题。解决办法请看Singleton5。
         */
        [[maybe_unused]] static Singleton1 *getInstance() {
            if (nullptr == instance) {  //如果已经创建了实例 再次访问不会被阻塞，减少代价
                std::lock_guard<std::mutex> lock(mutex);
                if (nullptr == instance) {
                    instance = new Singleton1();
                }
            }
            return instance;
        }

    private:
        Singleton1() = default;

        Singleton1(const Singleton1 &rhs) = default;

        static std::mutex mutex;
        static Singleton1 *instance;
    };

    //在外部 对静态变量进行初始化
    std::mutex Singleton1::mutex;
    Singleton1 *Singleton1::instance = nullptr;

} // Singleton

#endif //DESIGNPATTERN_SINGLETON1_H
